<template>
  <zb-popup ref="PopupModule" v-model="visible" :closeable="false" round position="bottom">
    <view class="zb-calendar">
      <view class="head">
        <view class="title">{{title}}</view>
        <view class="close" @click="close"></view>
      </view>
      <view class="content">
        <view class="date-info">
          <view class="prev-btn" @click="changeMonth(1)">
            <view class="arrow"></view>
          </view>
          <text>{{activeDate.year}}年{{activeDate.month}}月</text>
          <view class="next-btn" @click="changeMonth(2)">
            <view class="arrow"></view>
          </view>
        </view>
        <view class="week-list">
          <view class="item">日</view>
          <view class="item">一</view>
          <view class="item">二</view>
          <view class="item">三</view>
          <view class="item">四</view>
          <view class="item">五</view>
          <view class="item">六</view>
        </view>
        <swiper 
          v-if="dateList.length > 0" 
          class="my-swiper" 
          :current="activeIndex" 
          circular 
          vertical 
          skip-hidden-item-layout
          :duration="300"
          @animationfinish="animationfinish"
        >
          <swiper-item v-for="(sub,idx) in dateList" :key="idx">
            <view v-if="sub.list && sub.list.length > 0" class="date-list">
            <view class="month">{{Number(sub.month)}}</view>
              <view class="item" v-for="item in sub.first" :key="item"></view>
              <view 
                v-for="item in sub.list" 
                :key="item.date" 
                class="item" 
                :class="{
                  active: renderClass(item).active,
                  range: renderClass(item).range,
                  disabled: renderClass(item).disabled,
                  today: renderClass(item).today,
                }"
                @click="changeDate(item.date)"
              >
                {{item.day}}
                <text v-if="renderClass(item).today && (!renderClass(item).start && !renderClass(item).end)" class="extra">今天</text>
                <text v-if="renderClass(item).start || renderClass(item).end" class="extra">
                  <template v-if="renderClass(item).start">入住</template>
                  <template v-if="renderClass(item).start && renderClass(item).end">/</template>
                  <template v-if="renderClass(item).end">离开</template>
                </text>
              </view>
            </view>
          </swiper-item>
        </swiper>
      </view>
      <view class="foot">
        <zb-button block round :disabled="disabled" type="primary" @click="confirm">确定</zb-button>
      </view>
    </view>
  </zb-popup>
</template>

<script>
  export default {
    name: 'zb-calendar',
    props: {
      // multiple、range
      type: {
        type: String,
        default: '',
      },
      title: {
        type: String,
        default: '日期选择'
      },
      disabledDate: {
        type: Function,
        default: null,
      },
      value: {
        type: [Array,String],
        default: '',
      },
    },
    data() {
      return {
        visible: false,
        selectedDate: [],
        dateList: [],
        activeIndex: 1,
      };
    },
    computed: {
      activeDate() {
        if (this.dateList.length === 0) {
          return {};
        }
        return this.dateList[this.activeIndex];
      },
      disabled() {
        if (this.type === 'multiple') {
          return false;
        } else if (this.type === 'range') {
          if (this.selectedDate.length === 2) {
            return false;
          }
        } else {
          if (this.selectedDate.length === 1) {
            return false;
          }
        }
        return true;
      },
    },
    methods: {
      open() {
        this.visible = true;
        this.activeIndex = 1;
        const value = this.value;
        this.dateList = [];
        if (this.type) {
          this.selectedDate = [...value];
        } else {
          this.selectedDate = value ? [value] : [];
        }
        let active = new Date();
        if (this.selectedDate.length > 0) {
          active = new Date(this.selectedDate[this.selectedDate.length - 1]);
        }
        this.renderDate(active);
      },
      // 关闭弹窗
      close() {
        this.$refs.PopupModule.close();
      },
      confirm() {
        const val = [...this.selectedDate];
        this.$emit('input', this.type ? val : val[0] || '');
        this.close();
      },
      changeMonth(type) {
        let index = this.activeIndex
        if (type === 1) {
          // 上一月
          index --;
        } else {
          // 下一月
          index ++;
        }
        if (index < 0) {
          index = 2
        } else if (index > 2) {
          index = 0
        }
        this.animationfinish({ detail: { current: index } });
      },
      animationfinish(e) {
        this.activeIndex = e.detail.current;
        const active = new Date(`${this.activeDate.year}-${this.activeDate.month}-01`);
        this.renderDate(active);
      },
      renderDate(active) {
        const activeInfo = this.getDateInfo(active);
        activeInfo.month = Number(activeInfo.month);
        const prevInfo = {}, nextInfo = {};
        if (activeInfo.month === 1) {
          prevInfo.year = activeInfo.year - 1
          prevInfo.month = 12
          nextInfo.year = activeInfo.year
          nextInfo.month = activeInfo.month + 1
        } else if (activeInfo.month === 12) {
          prevInfo.year = activeInfo.year
          prevInfo.month = activeInfo.month - 1
          nextInfo.year = activeInfo.year + 1
          nextInfo.month = 1
        } else {
          prevInfo.year = activeInfo.year
          prevInfo.month = activeInfo.month - 1
          nextInfo.year = activeInfo.year
          nextInfo.month = activeInfo.month + 1
        }
        prevInfo.month = prevInfo.month < 10 ? '0' + prevInfo.month : prevInfo.month
        activeInfo.month = activeInfo.month < 10 ? '0' + activeInfo.month : activeInfo.month
        nextInfo.month = nextInfo.month < 10 ? '0' + nextInfo.month : nextInfo.month
        
        prevInfo.first = new Date(prevInfo.year, prevInfo.month - 1, 1).getDay()
        prevInfo.list = Array.from({length: new Date(prevInfo.year, prevInfo.month, 0).getDate()}, (v, i) => ({
          date: `${prevInfo.year}-${prevInfo.month}-${i + 1 < 10 ? '0' + (i + 1) : (i + 1)}`,
          day: i + 1,
        }))
        activeInfo.first = new Date(activeInfo.year, activeInfo.month - 1, 1).getDay()
        activeInfo.list = Array.from({length: new Date(activeInfo.year, activeInfo.month, 0).getDate()}, (v, i) => ({
          date: `${activeInfo.year}-${activeInfo.month}-${i + 1 < 10 ? '0' + (i + 1) : (i + 1)}`,
          day: i + 1,
        }))
        nextInfo.first = new Date(nextInfo.year, nextInfo.month - 1, 1).getDay()
        nextInfo.list = Array.from({length: new Date(nextInfo.year, nextInfo.month, 0).getDate()}, (v, i) => ({
          date: `${nextInfo.year}-${nextInfo.month}-${i + 1 < 10 ? '0' + (i + 1) : (i + 1)}`,
          day: i + 1,
        }))
        const dateList = Array.from({ lenght: 3 }, () => ({}))
        dateList[this.activeIndex] = activeInfo
        if (this.activeIndex === 0) {
          dateList[this.activeIndex + 1] = nextInfo
          dateList[this.activeIndex + 2] = prevInfo
        } else if (this.activeIndex === 2) {
          dateList[this.activeIndex - 2] = nextInfo
          dateList[this.activeIndex - 1] = prevInfo
        } else {
          dateList[this.activeIndex + 1] = nextInfo
          dateList[this.activeIndex - 1] = prevInfo
        }
        this.dateList = [...dateList];
      },
      renderClass(item) {
        const obj = {
          today: false,
          active: false,
          range: false,
          disabled: false,
          start: false,
          end: false,
        }
        if (this.selectedDate.includes(item.date)) {
          obj.active = true;
        }
        const todayStr = this.getDateInfo(new Date());
        if (`${todayStr.year}-${todayStr.month}-${todayStr.day}` === item.date) {
          obj.today = true;
        }
        if (this.type === 'range' && this.selectedDate.length > 0) {
          const start = new Date(this.selectedDate[0]).getTime(),
          val = new Date(item.date).getTime();
          if (val === start) {
            obj.start = true;
          }
          if (this.selectedDate.length === 2) {
            const end = new Date(this.selectedDate[1]).getTime();
            if (end === val) {
              obj.end = true;
            }
            if (val > start && val < end) {
              obj.range = true;
            }
          }
        }
        if (typeof this.disabledDate === 'function') {
          obj.disabled = this.disabledDate(item.date);
        }
        return obj
      },
      getDateInfo(val) {
        const y = val.getFullYear()
        const m = val.getMonth() + 1
        const d = val.getDate()
        return { 
          year: y,
          month: m < 10 ? '0' + m : m,
          day: d < 10 ? '0' + d : d,
        }
      },
      changeDate(val) {
        if (this.type === 'multiple') {
          if (this.selectedDate.includes(val)) {
            this.selectedDate = this.selectedDate.filter(v => v !== val);
          } else {
            this.selectedDate.push(val);
          }
        } else if (this.type === 'range') {
          if (this.selectedDate.length === 2) {
            this.selectedDate = [val];
          } else if (this.selectedDate.length === 1) {
            if (new Date(val).getTime() < new Date(this.selectedDate[0]).getTime()) {
              this.selectedDate = [val];
            } else {
              this.selectedDate.push(val);
            }
          } else {
            this.selectedDate = [val];
          }
        } else {
          this.selectedDate = [val];
        }
        this.selectedDate = this.selectedDate.sort();
      },
    },
  }
</script>

<style lang="scss">
.zb-calendar {
  font-family: Arial, Helvetica, sans-serif;
  .head {
    width: 100%;
    height: 88rpx;
    line-height: 88rpx;
    position: relative;
    .title {
      width: 100%;
      text-align: center;
      font-size: 32rpx;
      color: #333;
    }
    .close {
      @include close;
    }
  }
  .content {
    overflow: hidden;
    .date-info {
      text-align: center;
      font-size: 28rpx;
      line-height: 80rpx;
      color: #333;
      @include flex;
      .prev-btn {
        transform: rotate(180deg);
        width: 80rpx;
        height: 80rpx;
        @include flex;
        .arrow {
          @include arrow;
        }
      }
      .next-btn {
        width: 80rpx;
        height: 80rpx;
        @include flex;
        .arrow {
          @include arrow;
        }
      }
    }
    .week-list {
      @include flex;
      box-shadow: 0 8rpx 10rpx rgba(#000,.05);
      .item {
        flex: 1;
        overflow: hidden;
        text-align: center;
        font-size: 24rpx;
        line-height: 60rpx;
        color: #333;
      }
    }
    .my-swiper {
      width: 100%;
      height: 600rpx;
    }
    .date-list {
      overflow: hidden;
      width: 100%;
      height: 600rpx;
      position: relative;
      .month {
        font-size: 320rpx;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%,-50%);
        color: rgba(#000,.1);
      }
      .item {
        width: 14.28571%;
        float: left;
        height: 99rpx;
        line-height: 99rpx;
        text-align: center;
        font-size: 28rpx;
        position: relative;
        margin-bottom: 1rpx;
        &.today {
          color: $uni-color-error;
          font-weight: bold;
        }
        &.range {
          background-color: rgba($uni-color-primary, .1);
          color: $uni-color-primary;
          .extra {
            color: $uni-color-primary;
          }
        }
        &.active {
          background-color: $uni-color-primary;
          color: #fff;
          .extra {
            color: #fff;
          }
        }
        &.disabled {
          opacity: .4;
          pointer-events: none;
        }
        .extra {
          position: absolute;
          top: 64%;
          left: 50%;
          transform: translateX(-50%);
          font-size: 20rpx;
          line-height: 24rpx;
          height: 24rpx;
          color: $uni-color-error;
          font-weight: normal;
          white-space: nowrap;
        }
      }
    }
  }
  .foot {
    box-sizing: border-box;
    padding: 24rpx 28rpx;
  }
}
</style>
